/*
 * Copyright (c) 2013-2018 上海汇数数据. All rights reserved.
 * @(#) PaddingSchema.java 2018-08-06 17:26
 */

package cn.jh.common.core.crypto;

import org.jetbrains.annotations.NotNull;


/**
 * 填充（密码学）模式枚举。
 *
 * @author Fuchun
 * @since 1.0
 */
public enum PaddingSchema {

    /** 无填充。*/
    NONE("NoPadding"),

    /**
     * Padding scheme as defined in the W3C's &quot;XML Encryption Syntax and Processing&quot; document,
     * [Section 5.2 - Block Encryption Algorithms](http://www.w3.org/TR/xmlenc-core/#sec-Alg-Block).
     */
    ISO10126("ISO10126Padding"),

    /**
     * Optimal Asymmetric Encryption Padding defined in RSA's [PKSC#1
     * standard](http://en.wikipedia.org/wiki/PKCS1) (aka [RFC 3447](http://tools.ietf.org/html/rfc3447)).
     *
     * **NOTE:** using this padding requires initializing [Cipher][javax.crypto.Cipher] instances with a
     * [OAEPParameterSpec][javax.crypto.spec.OAEPParameterSpec] object which provides the
     * 1. message digest and
     * 2. mask generation function to use for the scheme.
     *
     * ===Convenient Alternatives===
     * While using this scheme enables you full customization of the message digest + mask generation function
     * combination, it does require the extra burden of providing your own `OAEPParameterSpec` object.  This is
     * often unnecessary, because most combinations are fairly standard.  These common combinations are pre-defined
     * in this enum in the `OAEP`* variants.
     *
     * If you find that these common combinations still do not meet your needs, then you will need to
     * specify your own message digest and mask generation function, either as an `OAEPParameterSpec` object
     * during Cipher initialization or, maybe more easily, in the scheme name directly.  If you want to use scheme name
     * approach, the name format is specified in the
     * [Standard Names](http://java.sun.com/javase/6/docs/technotes/guides/security/StandardNames.html)
     * document in the `Cipher Algorithm Padding` section.
     *
     * @see [OAEPWithMd5AndMgf1]
     * @see [OAEPWithSha1AndMgf1]
     * @see [OAEPWithSha256AndMgf1]
     * @see [OAEPWithSha384AndMgf1]
     * @see [OAEPWithSha512AndMgf1]
     */
    OAEP("OAEPPadding"),

    /**
     * Optimal Asymmetric Encryption Padding with `MD5` message digest and `MGF1` mask generation function.
     *
     *
     * This is a convenient pre-defined OAEP padding scheme that embeds the message digest and mask generation function.
     * When using this padding scheme, there is no need to init the `Cipher` instance with an
     * [OAEPParameterSpec][javax.crypto.spec.OAEPParameterSpec] object, as it is already 'built in' to the scheme
     * name (unlike the [OAEP][.OAEP] scheme, which requires a bit more work).
     */
    OAEPWithMd5AndMgf1("OAEPWithMD5AndMGF1Padding"),

    /**
     * Optimal Asymmetric Encryption Padding with `SHA-1` message digest and `MGF1` mask generation function.
     *
     *
     * This is a convenient pre-defined OAEP padding scheme that embeds the message digest and mask generation function.
     * When using this padding scheme, there is no need to init the `Cipher` instance with an
     * [OAEPParameterSpec][javax.crypto.spec.OAEPParameterSpec] object, as it is already 'built in' to the scheme
     * name (unlike the [OAEP][.OAEP] scheme, which requires a bit more work).
     */
    OAEPWithSha1AndMgf1("OAEPWithSHA-1AndMGF1Padding"),

    /**
     * Optimal Asymmetric Encryption Padding with `SHA-256` message digest and `MGF1` mask generation function.
     *
     *
     * This is a convenient pre-defined OAEP padding scheme that embeds the message digest and mask generation function.
     * When using this padding scheme, there is no need to init the `Cipher` instance with an
     * [OAEPParameterSpec][javax.crypto.spec.OAEPParameterSpec] object, as it is already 'built in' to the scheme
     * name (unlike the [OAEP][.OAEP] scheme, which requires a bit more work).
     */
    OAEPWithSha256AndMgf1("OAEPWithSHA-256AndMGF1Padding"),

    /**
     * Optimal Asymmetric Encryption Padding with `SHA-384` message digest and `MGF1` mask generation function.
     *
     *
     * This is a convenient pre-defined OAEP padding scheme that embeds the message digest and mask generation function.
     * When using this padding scheme, there is no need to init the `Cipher` instance with an
     * [OAEPParameterSpec][javax.crypto.spec.OAEPParameterSpec] object, as it is already 'built in' to the scheme
     * name (unlike the [OAEP][.OAEP] scheme, which requires a bit more work).
     */
    OAEPWithSha384AndMgf1("OAEPWithSHA-384AndMGF1Padding"),

    /**
     * Optimal Asymmetric Encryption Padding with `SHA-512` message digest and `MGF1` mask generation function.
     *
     *
     * This is a convenient pre-defined OAEP padding scheme that embeds the message digest and mask generation function.
     * When using this padding scheme, there is no need to init the `Cipher` instance with an
     * [OAEPParameterSpec][javax.crypto.spec.OAEPParameterSpec] object, as it is already 'built in' to the scheme
     * name (unlike the [OAEP][.OAEP] scheme, which requires a bit more work).
     */
    OAEPWithSha512AndMgf1("OAEPWithSHA-512AndMGF1Padding"),

    /**
     * Padding scheme used with the {@code RSA} algorithm defined in RSA's
     * <a href="http://en.wikipedia.org/wiki/PKCS1">PKSC#1 standard</a> (aka
     * <a href="http://tools.ietf.org/html/rfc3447">RFC 3447</a>).
     */
    PKCS1("PKCS1Padding"),

    /**
     * If the block length is B then add N padding bytes of value N to make
     * the input length up to the next exact multiple of B.
     * If the input length is already an exact multiple of B then add B bytes of value B.
     * Thus padding of length N between one and B bytes is always added in an unambiguous manner.
     * After decrypting, check that the last N bytes of the decrypted data all have value
     * N with `1 < N ≤ B`. If so, strip N bytes, otherwise throw a decryption error.
     *
     * Examples of PKCS5 padding for block length N = 8:
     *
     *     3 bytes: FDFDFD           --> FDFDFD0505050505
     *     7 bytes: FDFDFDFDFDFDFD   --> FDFDFDFDFDFDFD01
     *     8 bytes: FDFDFDFDFDFDFDFD --> FDFDFDFDFDFDFDFD0808080808080808
     */
    PKCS5("PKCS5Padding"),

    /**
     * PKCS #7: Cryptographic Message Syntax. see [RFC2315](https://tools.ietf.org/html/rfc2315)
     */
    PKCS7("PKCS7Padding")
    ;

    final String text;

    PaddingSchema(String text) {
        this.text = text;
    }

    @NotNull
    public static PaddingSchema forString(String name) {
        String nameText;
        if (name == null || (nameText = name.trim()).isEmpty()) return NONE;
        String nameUpper = nameText.toUpperCase();
        for (PaddingSchema padding : values()) {
            if (padding.name().equals(nameUpper) ||
                    padding.text.equals(nameText)) {
                return padding;
            }
        }
        return NONE;
    }
}
